package agent_service

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"strings"

	"agent/agent-prompt/business"
	"github.com/cloudwego/eino-ext/components/model/openai"
)

// JokeAgent 笑话智能体，继承自BaseAgent
// 专门用于生成各种类型的笑话，提供统一的笑话生成接口

type JokeAgent struct {
	// 嵌入BaseAgent，继承其所有字段和方法
	*BaseAgent
	// 当前笑话风格设置
	style string
}

// NewJokeAgent 创建一个新的笑话智能体实例
// 参数：
//   - model: 语言模型实例
// 返回值：
//   - *JokeAgent: 初始化后的笑话智能体实例

func NewJokeAgent(model *openai.ChatModel) *JokeAgent {
	// 初始化基础智能体
	baseAgent := NewBaseAgent(model, "你是一位幽默风趣的笑话创作者。请创作简洁有趣的笑话。", nil)

	// 创建并返回笑话智能体实例
	jokeAgent := &JokeAgent{
		BaseAgent: baseAgent,
		style:     "", // 默认不设置特定风格
	}

	log.Println("笑话智能体初始化成功")
	return jokeAgent
}

// GenerateJokes 生成笑话（统一方法）
// 参数：
//   - ctx: 上下文
//   - count: 要生成的笑话数量
//   - style: 笑话风格
//   - topic: 笑话主题
// 返回值：
//   - []string: 生成的笑话列表
//   - error: 错误信息
// 功能：根据参数生成指定数量、风格和主题的笑话
func (ja *JokeAgent) GenerateJokes(ctx context.Context, count int, style string, topic string) ([]string, error) {
	// 清空之前可能存在的对话历史
	ja.ClearHistory()

	// 如果style为空，使用智能体当前设置的风格
	if style == "" {
		style = ja.style
	}

	// 使用统一的提示词函数
	ja.Prompt = business.MultiJokePrompt(count, style, topic)

	// 构建请求内容
	requestText := fmt.Sprintf("请生成%d个笑话", count)
	if topic != "" {
		requestText = fmt.Sprintf("请围绕'%s'主题生成%d个笑话", topic, count)
	}

	// 生成笑话
	resp, err := ja.GenerateResponse(ctx, requestText)
	if err != nil {
		log.Printf("生成笑话失败 (数量: %d, 主题: %s): %v", count, topic, err)
		return nil, err
	}

	// 分割响应内容为笑话列表
	jokes := ja.splitJokesResponse(resp.Content)

	log.Printf("成功生成笑话，数量: %d, 主题: %s", count, topic)
	return jokes, nil
}

// splitJokesResponse 分割多笑话响应内容
// 参数：
//   - content: 生成的多个笑话内容
// 返回值：
//   - []string: 分割后的笑话列表
// 功能：将文本内容按序号分割成单个笑话列表

func (ja *JokeAgent) splitJokesResponse(content string) []string {
	// 这里可以实现更复杂的分割逻辑
	// 按行分割
	lines := strings.Split(content, "\n")
	var jokes []string
	var currentJoke strings.Builder

	// 按序号分割笑话
	for _, line := range lines {
		trimmedLine := strings.TrimSpace(line)
		if trimmedLine == "" {
			continue
		}

		// 检查是否是新笑话的开始（以数字开头后跟标点）
		if len(trimmedLine) > 2 &&
			(trimmedLine[0] >= '1' && trimmedLine[0] <= '9') &&
			(strings.HasPrefix(trimmedLine[1:], ".") || strings.HasPrefix(trimmedLine[1:], "、") || strings.HasPrefix(trimmedLine[1:], "）") || strings.HasPrefix(trimmedLine[1:], ")")) {

			// 如果当前笑话不为空，添加到结果列表
			if currentJoke.Len() > 0 {
				jokes = append(jokes, strings.TrimSpace(currentJoke.String()))
				currentJoke.Reset()
			}

			// 开始新笑话，移除序号前缀
			currentJoke.WriteString(trimmedLine[2:])
		} else if currentJoke.Len() > 0 {
			// 继续添加到当前笑话
			currentJoke.WriteString("\n")
			currentJoke.WriteString(trimmedLine)
		} else {
			// 如果不是以序号开头，且当前没有笑话在构建，则添加为第一个笑话
			currentJoke.WriteString(trimmedLine)
		}
	}

	// 添加最后一个笑话
	if currentJoke.Len() > 0 {
		jokes = append(jokes, strings.TrimSpace(currentJoke.String()))
	}

	// 如果没有识别到分割的笑话，返回原始内容
	if len(jokes) == 0 {
		return []string{content}
	}

	return jokes
}

// 笑话智能体特有错误定义
var (
	ErrInvalidJokeCount = &AgentError{"无效的笑话数量，必须在1-10之间"}
)

// SetJokeStyle 设置笑话风格
// 参数：
//   - style: 笑话风格 (例如: "冷笑话", "生活笑话", "谐音梗"等)
// 功能：调整提示词以生成特定风格的笑话

func (ja *JokeAgent) SetJokeStyle(style string) {
	// 更新智能体的风格设置
	ja.style = style
	// 使用MultiJokePrompt函数更新提示词
	ja.Prompt = business.MultiJokePrompt(1, style, "")
	log.Printf("笑话风格已设置为: %s", style)
}

// IntentType 定义意图类型枚举

type IntentType string

const (
	IntentRandomJoke IntentType = "random_joke"
	IntentTopicJoke  IntentType = "topic_joke"
	IntentMultiJoke  IntentType = "multi_joke"
	IntentUnknown    IntentType = "unknown"
)

// JokeIntent 笑话意图结构
// 用于存储从用户输入中识别出的笑话请求意图和相关参数
type JokeIntent struct {
	Type  IntentType `json:"type"`
	Topic string     `json:"topic"`
	Count int        `json:"count"`
	Style string     `json:"style"`
}

// RecognizeIntent 识别用户输入的笑话相关意图
// 参数：
//   - ctx: 上下文
//   - userInput: 用户输入内容
// 返回值：
//   - *JokeIntent: 识别到的意图信息
//   - error: 错误信息
// 功能：使用大模型分析用户输入，识别用户的笑话请求意图

func (ja *JokeAgent) RecognizeIntent(ctx context.Context, userInput string) (*JokeIntent, error) {
	// 使用独立的提示词函数获取意图识别提示词
	intentPrompt := business.JokeIntentPrompt(userInput)
	log.Printf("使用提示词进行意图识别: %s", intentPrompt)

	// 使用模型进行意图识别
	ja.ClearHistory()
	resp, err := ja.GenerateResponse(ctx, intentPrompt)
	if err != nil {
		log.Printf("意图识别失败: %v", err)
		return nil, err
	}

	log.Printf("模型意图识别响应: %s", resp.Content)

	// 解析模型输出，提取意图信息
	intent := ja.parseIntentFromResponse(resp.Content, userInput)

	// 转换意图类型字符串为IntentType类型常量
	intent.Type = ja.convertIntentType(string(intent.Type))

	log.Printf("识别到意图: %v", intent)
	return intent, nil
}

// convertIntentType 将意图类型字符串转换为IntentType枚举类型
// 参数：
//   - typeStr: 意图类型字符串
// 返回值：
//   - IntentType: 对应的枚举类型常量
func (ja *JokeAgent) convertIntentType(typeStr string) IntentType {
	// 根据常见的意图类型字符串映射到枚举类型
	switch strings.ToLower(typeStr) {
	case "random_joke", "随机笑话", "普通笑话":
		return IntentRandomJoke
	case "topic_joke", "主题笑话", "指定主题笑话":
		return IntentTopicJoke
	case "multi_joke", "多笑话", "多个笑话":
		return IntentMultiJoke
	default:
		return IntentUnknown
	}
}

// parseIntentFromResponse 解析模型响应，提取笑话意图信息
// 参数：
//   - modelOutput: 模型的输出内容
//   - userInput: 用户原始输入
// 返回值：
//   - *JokeIntent: 解析得到的意图信息
func (ja *JokeAgent) parseIntentFromResponse(modelOutput string, userInput string) *JokeIntent {
	// 默认意图
	intent := &JokeIntent{
		Type:  IntentRandomJoke,
		Topic: "",
		Count: 1,
		Style: "",
	}

	// 尝试JSON解析
	var jsonIntent JokeIntent
	if err := json.Unmarshal([]byte(modelOutput), &jsonIntent); err == nil {
		// JSON解析成功，使用解析结果
		intent = &jsonIntent
		// 确保默认值合理
		if intent.Count <= 0 || intent.Count > 10 {
			intent.Count = 1
		}
		// 如果类型为空或未知，尝试推断
		if intent.Type == "" || intent.Type == IntentUnknown {
			intent.Type = ja.inferIntentTypeFromParams(intent)
		}
		log.Printf("通过JSON解析识别到意图: %+v", intent)
		return intent
	}

	// JSON解析失败，使用关键词匹配作为fallback
	return ja.fallbackIntentRecognition(userInput)
}

// inferIntentTypeFromParams 根据意图参数推断意图类型
// 参数：
//   - intent: 包含参数的意图对象
// 返回值：
//   - IntentType: 推断的意图类型
func (ja *JokeAgent) inferIntentTypeFromParams(intent *JokeIntent) IntentType {
	// 根据参数推断意图类型
	if intent.Count > 1 {
		return IntentMultiJoke
	}
	if intent.Topic != "" {
		return IntentTopicJoke
	}
	return IntentRandomJoke
}

// fallbackIntentRecognition 使用关键词匹配进行意图识别的fallback方法
// 参数：
//   - userInput: 用户原始输入
// 返回值：
//   - *JokeIntent: 识别得到的意图信息
func (ja *JokeAgent) fallbackIntentRecognition(userInput string) *JokeIntent {
	intent := &JokeIntent{
		Type:  IntentRandomJoke,
		Topic: "",
		Count: 1,
		Style: "",
	}

	userInput = strings.ToLower(userInput)

	// 检查是否请求多个笑话
	countKeywords := []string{"两个", "三个", "四个", "五个", "六个", "七个", "八个", "九个", "十个",
		"2个", "3个", "4个", "5个", "6个", "7个", "8个", "9个", "10个",
		"2个笑话", "3个笑话", "4个笑话", "5个笑话", "6个笑话", "7个笑话", "8个笑话", "9个笑话", "10个笑话"}
	countMap := map[string]int{
		"两个": 2, "三个": 3, "四个": 4, "五个": 5, "六个": 6, "七个": 7, "八个": 8, "九个": 9, "十个": 10,
		"2个": 2, "3个": 3, "4个": 4, "5个": 5, "6个": 6, "7个": 7, "8个": 8, "9个": 9, "10个": 10,
		"2个笑话": 2, "3个笑话": 3, "4个笑话": 4, "5个笑话": 5, "6个笑话": 6, "7个笑话": 7, "8个笑话": 8, "9个笑话": 9, "10个笑话": 10,
	}

	for _, keyword := range countKeywords {
		if strings.Contains(userInput, strings.ToLower(keyword)) {
			intent.Count = countMap[keyword]
			intent.Type = IntentMultiJoke
			break
		}
	}

	// 检查是否指定主题
	topicKeywords := []string{"关于", "关于", "围绕", "围绕", "主题是", "主题是"}
	for _, keyword := range topicKeywords {
		if idx := strings.Index(userInput, keyword); idx != -1 {
			// 提取主题
			topicPart := strings.TrimSpace(userInput[idx+len(keyword):])
			// 简单处理：移除最后的标点符号和"笑话"相关词
			for _, suffix := range []string{"笑话", "的笑话", "？", "。", "!", "!"} {
				topicPart = strings.TrimSuffix(topicPart, suffix)
			}
			intent.Topic = strings.TrimSpace(topicPart)
			// 如果之前没有被识别为多笑话，则设为主题笑话
			if intent.Type != IntentMultiJoke {
				intent.Type = IntentTopicJoke
			}
			break
		}
	}

	// 检查是否指定风格
	availableStyles := ja.GetAvailableStyles()
	for _, style := range availableStyles {
		if strings.Contains(userInput, style) {
			intent.Style = style
			break
		}
	}

	log.Printf("通过关键词匹配识别到意图: %+v", intent)
	return intent
}

// HandleUserInput 处理用户输入，根据识别到的意图调用统一的笑话生成方法
// 参数：
//   - ctx: 上下文
//   - userInput: 用户输入内容
// 返回值：
//   - string: 生成的笑话内容或提示信息
//   - bool: 是否是笑话请求
//   - error: 错误信息
// 功能：统一的用户输入入口，处理所有笑话相关的用户请求
func (ja *JokeAgent) HandleUserInput(ctx context.Context, userInput string) (string, bool, error) {
	// 识别用户意图
	intent, err := ja.RecognizeIntent(ctx, userInput)
	if err != nil {
		return "识别意图失败，请重新输入", false, err
	}

	// 临时保存原始风格设置
	originalStyle := ja.style

	// 如果意图中指定了风格，临时应用该风格
	if intent.Style != "" && intent.Style != originalStyle {
		log.Printf("临时应用风格: %s", intent.Style)
		ja.style = intent.Style
		// 确保函数结束时恢复原始风格
		defer func() {
			ja.style = originalStyle
			log.Printf("恢复原始风格: %s", originalStyle)
		}()
	}

	// 确保数量在合理范围内
	if intent.Count <= 0 || intent.Count > 10 {
		intent.Count = 1
		log.Println("笑话数量超出范围，调整为1")
	}

	// 使用统一的笑话生成方法
	jokes, err := ja.GenerateJokes(ctx, intent.Count, intent.Style, intent.Topic)
	if err != nil {
		return "生成笑话失败", false, err
	}

	// 构建响应
	response := strings.Builder{}
	for i, joke := range jokes {
		response.WriteString(fmt.Sprintf("%d. %s\n\n", i+1, joke))
	}

	return response.String(), true, nil
}

// GetAvailableStyles 获取系统支持的笑话风格列表
// 返回值：
//   - []string: 风格名称列表
func (ja *JokeAgent) GetAvailableStyles() []string {
	styles := []string{}
	styles = append(styles, "冷笑话")
	styles = append(styles, "幽默笑话")
	styles = append(styles, "生活笑话")
	styles = append(styles, "谐音梗")
	styles = append(styles, "黑色幽默")
	styles = append(styles, "动物笑话")
	styles = append(styles, "儿童笑话")
	styles = append(styles, "职场笑话")
	styles = append(styles, "校园笑话")
	styles = append(styles, "网络热梗")
	return styles
}
